#pragma once
#include <mutex>

#if 0
template <class T>
class mySmartPtr
{
public:
    mySmartPtr(T *ptr)
        : _ptr(ptr) {}

    ~mySmartPtr()
    {
        if (_ptr != nullptr)
            delete _ptr;
        _ptr = nullptr;
    }

    // 再拷贝构造函数中完成这个操作

    T &operator*()
    {
        return *_ptr;
    }

    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
#elif 0
template <class T>
class myAutoPtr
{
public:
    myAutoPtr(T *ptr)
        : _ptr(ptr) {}

    ~myAutoPtr()
    {
        if (_ptr != nullptr)
            delete _ptr;
        _ptr = nullptr;
    }

    // 拷贝构造函数
    myAutoPtr(myAutoPtr<T> &aptr)
        : _ptr(aptr._ptr)
    {
        aptr._ptr = nullptr;
    }

    // operator重载
    myAutoPtr<T> &operator=(myAutoPtr<T> &aptr)
    {
        if (this != &aptr)
        {
            if (aptr != nullptr)
            {
                delete _ptr;
                _ptr = aptr._ptr;
                aptr._ptr = nullptr;
            }
        }
        return *this;
    }

    T &operator*()
    {
        return *_ptr;
    }

    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
#elif 0
template <class T>
class myUniquePtr
{
public:
    myUniquePtr(T *ptr)
        : _ptr(ptr) {}

    ~myUniquePtr()
    {
        if (_ptr != nullptr)
            delete _ptr;
        _ptr = nullptr;
    }
    // 禁用拷贝构造和赋值重载
    myUniquePtr(myUniquePtr<T> &mup) = delete;
    myUniquePtr<T> &operator=(myUniquePtr<T> &mup) = delete;

    T &operator*()
    {
        return *_ptr;
    }

    T *operator->()
    {
        return _ptr;
    }

private:
    T *_ptr;
};
#else
template <class T>
class mySharedPtr
{
public:
    mySharedPtr(T *ptr)
        : _ptr(ptr), _count(new int), _lock(new std::mutex) {}

    ~mySharedPtr()
    {
        release();
    }

    mySharedPtr(mySharedPtr<T> &mup)
        : _ptr(mup._ptr), _count(mup._count), _lock(mup._lock) // 初始化ptr和count保证二者一致
    {
        // 增加引用计数
        add_ref_count();
    }

    mySharedPtr<T> &operator=(mySharedPtr<T> &mup)
    {
        if (this != &mup)
        {
            // 如果自己有管理的对象的话，需要释放自己的资源
            release();

            // 更新所有的资源
            _ptr = mup._ptr;
            _count = mup._count;
            _lock = mup._lock;

            // 增加引用计数
            add_ref_count();
        }
        return *this;
    }

    T &operator*()
    {
        return *_ptr;
    }

    T *operator->()
    {
        return _ptr;
    }

private:
    // 增加引用计数
    void add_ref_count()
    {
        // 注意加锁
        std::unique_lock<std::mutex> ul(*_lock);
        (*_count)++;
    }

    // 释放自己的资源,引用计数--，为0释放所有资源，不为0，啥都不做
    void release()
    {
        bool flag = false;
        {
            std::unique_lock<std::mutex> ul(*_lock);
            if (--(*_count) == 0 && _ptr != nullptr)
            {
                // 说明引用计数为0，需要释放指向的对象
                if (_ptr != nullptr)
                    delete _ptr;
                _ptr = nullptr;

                // 同时需要释放引用计数
                delete _count;
                _count = nullptr;

                // 处于加锁状态，不可释放锁的资源
                // 通过标志位来释放锁资源
                flag = true;
            }
        }

        // 释放锁资源
        if (flag)
            delete _lock;
    }

private:
    T *_ptr;
    int *_count;       // 共享计数
    std::mutex *_lock; // 互斥锁
};
#endif